/**
 * [1 Timothy 3:16-17 ESV]
 * All Scripture is breathed out by God and profitable
 * for teaching, for reproof, for correction, and for training in righteousness,
 * that the man of God may be complete, equipped for every good work.
 *
 * BibleReader is an simple application for you to study God's Word.
 * The main user of this application maybe the pastor who's main language
 * is Chinese.
 *
 * You can use it totally free, and if you want to get source code of
 * this application, please email me at dweng123@gmail to get the source
 * code.
 *
 * \author dweng
 * \version 0.0.5
 * \date 2017-10-31
 */
#include "biblereaderapp.h"
#include "biblereaderverseheaderparser.h"
#include <QTextCodec>
#include <QTimer>
#include <QDir>
#include <QFile>
#include <QClipboard>
#include <QCursor>

// for logging
#include "Logger.h"
#include "FileAppender.h"

QtAwesome *BibleReaderApp::awesome = new QtAwesome(qApp);

BibleReaderApp::BibleReaderApp(int argc, char **argv):
    QApplication(argc, argv)
{
    globalTip = nullptr;

    //AltPressed = false;
    clipboardText = qApp->clipboard()->text();

    // set fontawesome icons
    awesome->initFontAwesome();
    awesome->setDefaultOption( "color", QColor(70,70,70));
    awesome->setDefaultOption( "color-disabled", QColor(70,70,70,60));
    awesome->setDefaultOption( "color-active", QColor(10,10,10));
    awesome->setDefaultOption( "color-selected", QColor(50,50,50));

#if QT_VERSION < 0x050000
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
#endif

#ifdef Q_OS_LINUX
    setFont(QFont(QString("Noto Sans CJK SC"), 10));
#endif
    splash = new QSplashScreen; // create a QSplashScreen
    splash->setPixmap(QPixmap(":/img/assets/images/splash.png"));
    splash->show();
    splash->raise();
    qApp->processEvents();

    // logging
    QDir dir(QApplication::applicationDirPath());
#ifdef Q_OS_OSX
    dir.cdUp();
    dir.cd("Resources");
#endif
    FileAppender* fileAppender = new FileAppender(dir.absolutePath() + "/debug.log");
    fileAppender->setFormat("[%{time}{yyyy-MM-ddTHH:mm:ss.zzz}] [%{type:-7}] <%{Function}> %{message}\n");
    logger->registerAppender(fileAppender);
    LOG_INFO("Bible Reader started!");

    LOG_INFO() << "Loading translations...";
    splash->showMessage(tr("Loading translations..."), Qt::AlignBottom|Qt::AlignLeft, Qt::blue);
    this->processEvents();
    LOG_INFO() << "Loading ZH_cn:" << translator.load(dir.absolutePath() + "/translations/ZH_cn.qm");
    LOG_INFO() << "Loading Qt ZH_cn:" << qtTranslator.load(dir.absolutePath() + "/translations/qt_zh_CN.qm");
    LOG_INFO() << "loading updater ZH_cn:" << updaterTranslator.load(dir.absolutePath() + "/translations/updater_zh_CN.qm");
    installTranslator(&translator);
    installTranslator(&qtTranslator);
    installTranslator(&updaterTranslator);

    // init biblereadercore
    splash->showMessage(tr("Loading modules..."), Qt::AlignBottom|Qt::AlignLeft, Qt::white);
    this->processEvents();
    this->brCore = new BibleReaderCore();
    connect(brCore, SIGNAL(loadResourceFinished(QString)), this, SLOT(showSplashMessage(QString)));
    connect(brCore, SIGNAL(bibleRemoved(QString)), this, SLOT(reboot()));

    initBibleReaderCore();

    // start clipboard monitor
    stateClipboardMonitor(brCore->getConfigurator()->getEnableClipboardMonitor());
    // connect signal of configurator of clipboard monitor
    connect(brCore->getConfigurator(), &BibleReaderConfigurator::clipboardMonitorChanged,
            this, &BibleReaderApp::stateClipboardMonitor);

    setApplicationName(tr("biblereader"));
    setApplicationVersion("0.6.0");
    setApplicationDisplayName(tr("biblereader"));
    setOrganizationDomain("biblereader.cn");
    setOrganizationName(tr("Bible Reader"));

#ifdef Q_OS_OSX
    qputenv("QT_MAC_WANTS_LAYER", "1");
#endif

    // Initialize objects
    splash->showMessage(tr("Building layout..."), Qt::AlignBottom|Qt::AlignLeft, Qt::white);
    this->processEvents();
    LOG_INFO() << "creating main window";
    w = new BibleReaderMainWindow(brCore);
    LOG_INFO() << "main window created";
    w->show();
    //QTimer::singleShot(5000, splash, SLOT(close()));
    splash->finish(w);
}

BibleReaderApp::~BibleReaderApp()
{
    if (w) {
        delete w;
    }

    if (splash) {
        delete splash;
    }

    if (globalTip) {
        globalTip->deleteLater();
    }
    deinitBibleReaderCore();
}

bool BibleReaderApp::initBibleReaderCore()
{
    this->brCore->init();
    return true;
}

bool BibleReaderApp::deinitBibleReaderCore()
{
    delete brCore;
    return true;
}

void BibleReaderApp::showSplashMessage(QString msg)
{
    if (splash) {
        splash->showMessage(tr("Loading %1").arg(msg), Qt::AlignBottom|Qt::AlignLeft,
                            Qt::white);
        qApp->processEvents();
    }
}

void BibleReaderApp::reboot()
{
    qApp->exit(773);
}

void BibleReaderApp::showVerseTipGlobal(QString text, QPoint pos)
{
    if (!globalTip) {
        globalTip = new BibleReaderToolTip();
        globalTip->setTextFont(QFont(brCore->getConfigurator()->getTipTextFontFamily(),
                                 brCore->getConfigurator()->getTipTextFontSize()));
    }

    globalTip->showText(pos, text, 100000);
}

void BibleReaderApp::checkClipboard()
{
    //if (!AltPressed) return;

    QString newText = qApp->clipboard()->text();

    if (newText != clipboardText) {
        if (globalTip) {
            globalTip->hide();
        }

        QVector<BibleVersePos> vposes = BibleReaderVerseHeaderParser::parse(newText);
        if (vposes.size() == 1) {
            // -1 means current book id
            if (vposes[0].getBookNumber() == -1) {
                vposes[0].setBookNumber(brCore->getCurrentBookNumber());
            }
            showVerseTipGlobal(brCore->getVerse(vposes[0].getBookNumber(),
                                    vposes[0].getChapterNumber(), vposes[0].getVerseNumber())
                    .textForRef().replace("[", "<font color='green'>[")
                    .replace("]", "]</font>")
                    .replace("{", "")
                    .replace("}", ""), QCursor::pos());
        } else if (vposes.size() == 2) {
            // -1 means current book id
            if (vposes[0].getBookNumber() == -1) {
                vposes[0].setBookNumber(brCore->getCurrentBookNumber());
                vposes[1].setBookNumber(brCore->getCurrentBookNumber());
            }
            showVerseTipGlobal(brCore->getVerses(vposes[0], vposes[1])
                    .replace("\n", "")
                   .replace("[", "<font color='green'><sup>[")
                   .replace("]", "]</sup></font>")
                   .replace("{", "")
                   .replace("}", ""), QCursor::pos());
        }

        clipboardText = newText;
    }
}

void BibleReaderApp::stateClipboardMonitor(bool state)
{
    if (state) {
        clipboardCheckTimer = startTimer(50);
        if (!clipboardCheckTimer) {
            LOG_ERROR() << "Clipboard check timer created failed";
        }
    } else {
        if (clipboardCheckTimer != 0) {
            killTimer(clipboardCheckTimer);
        }
    }
}

bool BibleReaderApp::notify(QObject *obj, QEvent *e)
{
//    if (e->type() == QEvent::KeyPress) {
//        if (static_cast<QKeyEvent *>(e)->key() == Qt::Key_Alt) {
//            AltPressed = true;
//        } else {
//            AltPressed = false;
//        }
//    }

//    if (e->type() == QEvent::KeyRelease) {
//        if (static_cast<QKeyEvent *>(e)->key() == Qt::Key_Alt) {
//            AltPressed = false;
//        }
//    }
    return QApplication::notify(obj,e);
}

bool BibleReaderApp::eventFilter(QObject *obj, QEvent *e)
{
    /*
    switch (e->type()) {
    case QEvent::KeyPress:
            if (obj->objectName() == "tipContent") {
                obj->event(e);
            }
        break;

    default:
        break;
    }
    */

    return QApplication::eventFilter(obj, e);
}

void BibleReaderApp::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == clipboardCheckTimer) {
        checkClipboard();
    } else {
        QApplication::timerEvent(event);
    }
}
